package chapter01.part12;

import chapter01.part2.CreateStream;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 约简操作 如果学过大数据的 Map-Reduce 就很好理解
 * reduce 是一种用于流计算的机制
 * 
 * 给定操作 op
 * 约简过程 v1 op v2 op v3 op ...
 * 提起操作函数 op(vi, vi+1) = vi op vi+1
 * 
 * 如果要使用并行流 必须考虑计算顺序与结果的影响
 * 
 * @author insight
 * @since 2021/7/23
 */
public class ReduceOperation {
    public static void main(String[] args) {
        // reduce() 有三种形式
        // 最简单的形式 使用一个二元函数 从前两个元素开始一直处理下去
        // 比如求和
        ArrayList<Integer> values = new ArrayList<>(2);
        for (int i = 1; i < 10; i++) {
            values.add(i);
        }
        // values.stream().reduce((x, y) -> x + y);
        Optional<Integer> sum = values.stream().reduce(Integer::sum);
        System.out.println(sum.orElse(0));

        // 第二种形式
        // 使用一个初值 e 作为起点 其中 e op x = x
        // 不再需要处理 Optional
        Integer sumOrZero = values.stream().reduce(0, Integer::sum);
        System.out.println(sumOrZero);

        // 第三种形式
        // 处理的类型和结果类型不同
        // 比如处理字符串 但是结果是字符串长度
        // 1. 提供一个累加器 (v1, v2) -> v1 + v2.length()
        // 2. 合并结果 (r1, r2) -> r1 + r2
        Supplier<Stream<String>> words = CreateStream.getWordsStream();
        
        List<String> collect = words.get().collect(Collectors.toList());
        System.out.println(collect);
        int cnt = 0;
        for (String s : collect) {
            cnt += s.length();
        }
        System.out.println("List Foreach: " + cnt);

        Integer ret = words.get().reduce(0,
                (pre, cur) -> pre + cur.length(),
                (pre1, cur2) -> pre1 + cur2);
        System.out.println("Reduce: " + ret);

        // 不涉及自动装箱 更高效
        int r2 = words.get().mapToInt(String::length).sum();
        System.out.println("MaptoInt: " + r2);
    }
}